/*
 * Copyright (c) 2013, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-web-praise nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.lpitools.gwtgui.client.components.querypanel;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.SuggestBox;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.QueryInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.UserInfo;
import com.sri.ai.lpitools.gwtgui.client.RPCService;
import com.sri.ai.lpitools.gwtgui.client.Toolkit;
import com.sri.ai.lpitools.gwtgui.client.components.dialogs.MessageDialog;
import com.sri.ai.lpitools.gwtgui.client.components.manager.UserListener;
import com.sri.ai.lpitools.gwtgui.client.util.JSONUtil;

/**
 * This Panel is for placing the query selection / editing components integrated into the main UI panel
 * @author bellwein
 */
public class QueryPanel extends LayoutPanel implements UserListener{

	private static final String AD_HOC_QUERY_STRING = "Ad Hoc";

	private ListBox querySelectionBox;
	private SuggestBox queryText;
	
	private MultiWordSuggestOracle suggestBoxOracle = new MultiWordSuggestOracle();
		
	private List<String> queries;
	private final Toolkit toolkit;
	
	public QueryPanel(Toolkit tk) {
		this.toolkit = tk;

		this.querySelectionBox = new ListBox();
		this.querySelectionBox.addStyleName("aic-SelectionBox");
		
		this.queryText = new SuggestBox(suggestBoxOracle);
		this.queryText.setStyleName("aic-TextBox");
		queries = new ArrayList<String>();

		//add a change listener to the text box to update the querySelectionManager
		this.queryText.getValueBox().addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				toolkit.getQueryDataManager().setQueryText(queryText.getText());

			}
		});
		queryText.getValueBox().addKeyUpHandler(new KeyUpHandler(){
			@Override
			public void onKeyUp(KeyUpEvent event) {
	            if (event.getNativeKeyCode() != KeyCodes.KEY_ENTER) {
					querySelectionBox.setSelectedIndex(0);
	            }
			}
		});
		
		//add a selection listener to populate the querySelectionBox
		this.querySelectionBox.addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				int selectedIndex = querySelectionBox.getSelectedIndex();
				if (selectedIndex > 0) {
					String selectedName = querySelectionBox.getItemText(selectedIndex);
					toolkit.getQueryDataManager().setSelectedQueryName(selectedName);
					getQueryText(selectedName, toolkit.getUserManager().getCurrentUser().getUser());
				} else {
					//for the unselected (or Ad Hoc) case, set the selected query name to NULL
					toolkit.getQueryDataManager().setSelectedQueryName(null);
					setQueryText("");
				}
			}
		});

		MyHandler executeHandler = new MyHandler();
		
		queryText.getValueBox().addKeyUpHandler(executeHandler);
		querySelectionBox.addKeyUpHandler(executeHandler);
		
		//add a user changed listener
		toolkit.getUserManager().addUserListener(this);
		//if a user is logged in, then update the queries list
		loggedInUserChanged(toolkit.getUserManager().getCurrentUser());
		Button runQuery = new Button("Execute");
		runQuery.addStyleName("aic-ExecutionButton");
		runQuery.addClickHandler(executeHandler);
		//layout the components
		this.add(querySelectionBox);

		DockLayoutPanel hp = new DockLayoutPanel(Unit.PX);
		hp.addEast(runQuery, 100);
		hp.add(queryText);

		this.add(hp);
		this.setWidgetTopHeight(querySelectionBox, 0, Unit.PCT, 2, Unit.EM);
		this.setWidgetBottomHeight(hp, 0, Unit.PCT, 2, Unit.EM);
	}
	
	// Create a handler for the sendButton and nameField
    class MyHandler implements ClickHandler, KeyUpHandler {
        /**
         * Fired when the user clicks on the sendButton.
         */
        public void onClick(ClickEvent event) {
        	runQuery();
        }

        /**
         * Fired when the user types in the nameField.
         */
        public void onKeyUp(KeyUpEvent event) {
            if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
            	runQuery();
            }
        }
    
        private void runQuery() {
        	if(!queryText.getText().equalsIgnoreCase("")) {
        		toolkit.getAicManager().runQuery();
			} else {
				MessageDialog.showMessageDialog("Use must enter a query before executing it");
			}
        }
    }

    protected void getQueryText(String selectedName, String user) {
    	RPCService.Util.getInstance().getQuery(user, selectedName, new AsyncCallback<QueryInfo>() {
    		@Override
    		public void onSuccess(QueryInfo result) {
    			if (result != null) {
    				setQueryText(result.getQuery());
    			}
    		}

    		@Override
    		public void onFailure(Throwable caught) {
    			MessageDialog.showMessageDialog(caught.getMessage());
    		}
    	});
	}

	/**
	 * will query the aicManager for the list of queries for the given user
	 */
	protected void updateQueriesList() {
		querySelectionBox.clear();
		//add a special Ad Hock selection item
		querySelectionBox.addItem(AD_HOC_QUERY_STRING);
		
		//get the queries for this user
		for (String info : queries) {
			querySelectionBox.addItem(info);
		}
		
		querySelectionBox.setSelectedIndex(0);
	}
	
	@Override
	public void loggedInUserChanged(UserInfo newUser) {
		querySelectionBox.clear();
		setQueryText("");
		if(newUser != null){
			getQueryList(newUser.getUser());
		} else {
			queries = new ArrayList<String>();
		}
	}

	public void addToSuggestions(String suggestion) {
		suggestBoxOracle.add(suggestion);
	}
	
	protected void setQueryText(String text) {
		queryText.setText(text);
		toolkit.getQueryDataManager().setQueryText(text);
	}
	
	private void getQueryList(String user) {
		queries.clear();
		RPCService.Util.getInstance().getQueryList(user, new AsyncCallback<String>() {
			@Override
			public void onSuccess(String result) {
				if (result == null) {
					MessageDialog.showMessageDialog("Null response for getQueryList query");
					return;
				}
				if (result.startsWith("ERROR.")) {
					
				} else {
					List<QueryInfo> list = JSONUtil.getQueryInfoList(result);
					for(QueryInfo current: list){
						queries.add(current.getQueryTitle());
					}
				}
				updateQueriesList();
			}

			@Override
			public void onFailure(Throwable caught) {
				MessageDialog.showMessageDialog(caught.getMessage());
			}
		});
	}
}
